#ifndef __M_HOST_H__
#define __M_HOST_H__
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"

namespace pprmq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string& hname,const std::string& basedir,const std::string& dbfile)
            :_host_name(hname),
            _emp(std::make_shared<ExchangeManager>(dbfile)),
            _qmp(std::make_shared<QueueManager>(dbfile)),
            _bmp(std::make_shared<BindingManager>(dbfile)),
            _mmp(std::make_shared<MessageManager>(basedir))
        {
            //获取到所有的队列信息，通过队列名称恢复历史消息数据
            QueueMap qm = _qmp->allQueues();
            for(auto& m : qm)
            {
                _mmp->initQueueMessage(m.first);
            }
        }

        bool declareExchange(const std::string &name,
                             ExchangeType type,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            return _emp->declareExchange(name,type,durable,auto_delete,args);
        }

        // 删除交换机的时候，需要将交换机相关的绑定信息也删除
        void deleteExchange(const std::string &name)
        {
            _bmp->removeExchangeBindings(name);
            return _emp->deleteExchange(name);
        }

        // 判断交换机是否存在
        bool existsExchange(const std::string &name)
        {
            return _emp->exists(name);
        }

        Exchange::ptr selectExchange(const std::string &ename)
        {
            return _emp->selectExchange(ename);
        }

        bool declareQueue(const std::string &qname, 
                bool qdurable, 
                bool qexclusive,
                bool qauto_delete,
                const google::protobuf::Map<std::string, std::string> &qargs)
        {
            //初始化队列的消息句柄（消息的存储管理）
            //队列的创建
            _mmp->initQueueMessage(qname);
            return _qmp->declareQueue(qname,qdurable,qexclusive,qauto_delete,qargs);
        }

        // 删除队列
        void deleteQueue(const std::string &name)
        {
            // 删除的时候队列相关的数据有两个：队列的消息，队列的绑定信息
            _bmp->removeMsgQueueBindings(name);
            _mmp->destroyQueueMessage(name);
            return _qmp->deleteMsgQueue(name);
        }

        bool existsQueue(const std::string &name)
        {
            return _qmp->exists(name);
        }

        QueueMap allQueues()
        {
            return _qmp->allQueues();
        }   

        bool bind(const std::string &ename, const std::string &qname, const std::string &key)
        {
            Exchange::ptr ep = _emp->selectExchange(ename);
            if(ep.get() == nullptr)
            {
                DLOG("进行队列绑定失败,交换机%s不存在", ename.c_str());
                return false;
            }
            MsgQueue::ptr qp = _qmp->selectMsgQueue(qname);
            if(qp.get() == nullptr)
            {
                DLOG("进行队列绑定失败,队列%s不存在", qname.c_str());
                return false;
            }
            return _bmp->bind(ename,qname,key,ep->_durable && qp->_durable);
        }
        
        void unBind(const std::string &ename, const std::string &qname)
        {
            return _bmp->unBind(ename,qname);
        }

        // 得到交换机的绑定信息
        MsgQueueBindingMap exchangeBindings(const std::string &ename)
        {
            return _bmp->getExchangeBindings(ename);
        }
        // 该绑定消息是否存在
        bool existsBinding(const std::string &ename, const std::string &qname)
        {
            return _bmp->exists(ename,qname);
        }
        
        bool basicPublish(const std::string &qname, BasicProperties *bp, const std::string &body)
        {
            MsgQueue::ptr mqp = _qmp->selectMsgQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("发布消息失败，队列%s不存在", qname.c_str());
                return false;
            }
            return _mmp->insert(qname,bp,body,mqp->_durable);
        }

        MessagePtr basicConsume(const std::string &qname)
        {
            return _mmp->front(qname);
        }

        void basicAck(const std::string &qname, const std::string &msgid)
        {
            return _mmp->ack(qname,msgid);
        }

        void clear()
        {
            _emp->clear();
            _qmp->clear();
            _bmp->clear();
            _mmp->clear();
        }
    private:
        std::string _host_name;
        ExchangeManager::ptr _emp;
        QueueManager::ptr _qmp;
        BindingManager::ptr _bmp;
        MessageManager::ptr _mmp;
    };
}

#endif